#ifndef MY_TINY_WEB_SERVER_HTTP_CONN_H
#define MY_TINY_WEB_SERVER_HTTP_CONN_H
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include "locker.h"
#include "sql_connection_pool.h"

class http_conn {
public:
    static const int FILENAME_LEN = 200;        //最大文件名长度
    static const int READ_BUFFER_SIZE = 2048;   //读缓冲区大小
    static const int WRITE_BUFFER_SIZE = 1024;  //写缓冲区大小

    enum METHOD         //定义请求方法
    {
        GET = 0,
        POST,
        HEAD,
        PUT,
        DELETE,
        TRACE,
        OPTIONS,
        CONNECT,
        PATH
    };
    enum CHECK_STATE    //定义主状态机的状态， 分为在读请求行， 读请求头， 读请求体
    {
        CHECK_STATE_REQUESTLINE = 0,
        CHECK_STATE_HEADER,
        CHECK_STATE_CONTENT
    };
    enum HTTP_CODE  //定义HTTP结果状态码
    {
        NO_REQUEST,
        GET_REQUEST,
        BAD_REQUEST,
        NO_RESOURCE,
        FORBIDDEN_REQUEST,
        FILE_REQUEST,
        INTERNAL_ERROR,
        CLOSED_CONNECTION
    };
    enum LINE_STATUS    //定义从状态机的状态，分为当前行已完成， 当前行错误， 正在读入当前行
    {
        LINE_OK = 0,
        LINE_BAD,
        LINE_OPEN
    };
public:
    http_conn() {}
    ~http_conn() {}

public:
    void init(int sockfd, const sockaddr_in &addr);
    void close_conn(bool real_close = true);
    void process();
    bool read_once();
    bool write();
    sockaddr_in *get_address()
    {
        return &m_address;
    }
    void initmysql_result(connection_pool *connPool); //获取用户注册表（username, pswd

private:
    void init();
    HTTP_CODE process_read();   //解析http请求
    bool process_write(HTTP_CODE ret);  //填充http应答

    //给process_read来分析http请求
    HTTP_CODE parse_request_line(char *text);
    HTTP_CODE parse_headers(char *text);
    HTTP_CODE parse_content(char *text);
    HTTP_CODE do_request();
    char *get_line() { return m_read_buf + m_start_line; };
    LINE_STATUS parse_line();

    //给process_write调用回应
    void unmap();
    bool add_response(const char *format, ...);
    bool add_content(const char *content);
    bool add_status_line(int status, const char *title);
    bool add_headers(int content_length);
    bool add_content_type();
    bool add_content_length(int content_length);
    bool add_linger();
    bool add_blank_line();

public:
    static int m_epollfd;
    static int m_user_count;
    MYSQL *mysql;

private:
    //http的监听socket和对方socket地址
    int m_sockfd;
    sockaddr_in m_address;

    char m_read_buf[READ_BUFFER_SIZE];  //读缓冲
    int m_read_idx; //缓冲区已读的最后一个字节的下一个位置
    int m_checked_idx;  //当前正在分析的缓冲区位置
    int m_start_line;   //当前正在解析的行起始位置
    char m_write_buf[WRITE_BUFFER_SIZE];    //写缓冲
    int m_write_idx;    //写缓冲待发送字节数

    CHECK_STATE m_check_state;  //主状态机的状态
    METHOD m_method;            //http请求方法枚举类

    char m_real_file[FILENAME_LEN]; //客户请求内容的完整路径 = root + m_url
    char *m_url;    //客户请求文件名
    char *m_version;    //http版本协议号，仅支持1.1
    char *m_host;       //主机名
    int m_content_length;   //http请求的消息体的长度
    bool m_linger;      //是否长连接


    char *m_file_address;   //客户请求文件被mmap的位置
    struct stat m_file_stat;    //目标文件的状态

    //用writev来写，下面是两个所需要的成员
    struct iovec m_iv[2];
    int m_iv_count;

    int cgi;
    char *m_string;
    int bytes_to_send;
    int bytes_have_send;
};


#endif //MY_TINY_WEB_SERVER_HTTP_CONN_H
